
package plots;

import java.awt.Color;
import java.util.ArrayList;

import processing.core.PApplet;
import util.PickeableObject;

public class ParallelCoordinatesPlot extends PickeableObject{

	private String[] headers;
	private double[][] minMax;
	private ArrayList<ParallelCoordinatesPlotLine> lines;
	private PApplet mainApplet;
	private int posY;
	private int posX;
	private int width;
	private int height;
	private int horizontalGap; 
	private int verticalGap;

	private int axisColor;
	private int colorLine;
	private int colorSelected;
	private int colorText;
	private int colorBackground;

	private int lineLength;

	private int[] axisXPositions;

	private int axisYUpperPosition;
	private int axisYLowerPosition;

	private boolean withBackground;
	
	private boolean autoSelection;

	/**
	 * Creates a new Parallel coordinates plot
	 * @param mainApplet the applet where its going to be drawn
	 * @param headers headers of each coordinate
	 * @param minMax
	 * @param posX
	 * @param posY
	 * @param width
	 * @param nHeight
	 * @param horizontalGap
	 * @param verticalGap
	 * @param axisColor
	 */
	public ParallelCoordinatesPlot(PApplet mainApplet, String[] headers, double[][] minMax, int posX, int posY, int width, int nHeight, int horizontalGap, int verticalGap)
	{
		this.mainApplet = mainApplet;
		this.headers = headers;
		this.minMax = minMax;
		this.width = width;
		this.height = nHeight;
		this.horizontalGap = horizontalGap;
		this.verticalGap = verticalGap;
		this.posX = posX;
		this.posY = posY;
		this.axisColor = Color.WHITE.getRGB();
		this.colorLine = Color.WHITE.getRGB();
		this.colorSelected = Color.YELLOW.getRGB();
		this.colorText = Color.WHITE.getRGB();
		this.colorBackground = Color.DARK_GRAY.getRGB();
		this.withBackground = true;
		this.lines = new ArrayList<ParallelCoordinatesPlotLine>();
		this.axisXPositions = new int[headers.length];
		this.autoSelection = false;

		lineLength = height - (2*verticalGap);

		axisYUpperPosition = posY + verticalGap;
		axisYLowerPosition = posY + height - verticalGap;

		axisXPositions[0] = posX + horizontalGap;

		int axisGap = (int)((double)(width - (2*horizontalGap)) / (double)(headers.length - 1));
		for(int i = 2; i < headers.length; i++)
		{
			axisXPositions[i - 1] = posX + horizontalGap + ((i-1)*axisGap);
		}
		axisXPositions[headers.length - 1] = posX + (width - horizontalGap);
	}
	
	public void setNewData(String[] headers, double[][] minMax, double[][] data)
	{
		this.minMax = minMax;
		this.axisXPositions = new int[headers.length];

		lineLength = height - (2*verticalGap);

		axisYUpperPosition = posY + verticalGap;
		axisYLowerPosition = posY + height - verticalGap;

		axisXPositions[0] = posX + horizontalGap;

		int axisGap = (int)((double)(width - (2 * horizontalGap)) / (double)(headers.length - 1));
		for(int i = 2; i < headers.length; i++)
		{
			axisXPositions[i - 1] = posX + horizontalGap + ((i-1)*axisGap);
		}
		axisXPositions[headers.length - 1] = posX + (width - horizontalGap);
		
		setData(data);
	}

	public void withBackground(boolean background)
	{
		withBackground = background;
	}

	public void setData(double[][] data)
	{
		lines.clear();

		for(int i = 0; i < data.length; i++)
		{
			double[] lineData = data[i];
			int[][] points = new int[lineData.length][2];
			for(int j = 0; j < lineData.length; j++)
			{
				points[j][0] = axisXPositions[j];
				points[j][1] = posY + height - verticalGap - (int)PApplet.map((float)lineData[j], (float)minMax[j][0], (float)minMax[j][1], 0, (float)lineLength);
			}
			ParallelCoordinatesPlotLine line = new ParallelCoordinatesPlotLine(mainApplet, points);
			line.setBaseColor(colorLine);
			line.setSelectedColor(colorSelected);
			line.setId((i + 1) * 100);
			lines.add(line);

		}
	}



	public void setLineColor(int lineColor) {
		this.colorLine = lineColor;
	}


	public void setSelectedColor(int selectedColor) {
		this.colorSelected = selectedColor;
	}


	public void setTextColor(int textColor) {
		this.colorText = textColor;
	}


	public void setBackgroundColor(int backgroundColor) {
		this.colorBackground = backgroundColor;
	}


	public boolean mouseIsOver()
	{
		for(ParallelCoordinatesPlotLine l : lines)
		{
			if(l.mouseIsOver())
			{
				return true;
			}
		}
		return false;
	}

	public void deselectLines()
	{
		autoSelection = true;
		for(ParallelCoordinatesPlotLine line_i : lines)
		{
			line_i.setUnselected();
			line_i.setChanged();
		}
		
		drawAxis();
		drawLines();
	}
	
	public void setSelectedLines(int[] lineNumbers)
	{
		autoSelection = true;
		for(int i : lineNumbers)
		{
			lines.get(i).setSelected();
			lines.get(i).setChanged();
		}
		
		drawAxis();
		drawLines();
	}
	
	private void drawLines()
	{
		for(ParallelCoordinatesPlotLine line : lines)
		{
			if(!autoSelection)
			{
				line.mouseIsOverFeedback();
				
			}
			line.setChanged();
			line.drawLine();
		}
		autoSelection = false;
	}
	
	private void drawAxis()
	{
		if(withBackground)
		{
			mainApplet.fill(colorBackground);
			mainApplet.stroke(axisColor);
			mainApplet.strokeWeight(1);
			mainApplet.rect((float)posX, (float)posY, (float)width, (float)height);
		}
		for(int i = 0; i < axisXPositions.length; i++)
		{
			mainApplet.stroke(axisColor);
			mainApplet.strokeWeight(1);
			mainApplet.line(axisXPositions[i], axisYUpperPosition, axisXPositions[i], axisYLowerPosition);

			String header = headers[i] + "\n" + minMax[i][0] + " to " + minMax[i][1];
			float textWidth = mainApplet.textWidth(header);
			mainApplet.fill(colorText);
			mainApplet.text(header, axisXPositions[i] - (int)(textWidth/2),  axisYLowerPosition + 15);
		}
	}
	
	public void drawPlot()
	{
		if(changed)
		{
//			System.out.println("drawn");
			drawAxis();
			if(!lines.isEmpty())
			{
				drawLines();
			}
			changed = false;
		}
	}
}
